package cn.itcast.protocol;

import cn.itcast.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

@Slf4j
//@ChannelHandler.Sharable
public class MessageCodec extends ByteToMessageCodec<Message> {

    @Override
    public void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
        // 1. 4 设置魔数 4个字节
        out.writeBytes(new byte[]{'i', 'K', 'U', 'N'});
        // 2. 1 字节的 版本号
        out.writeByte(1);
        // 3. 1 字节的序列化方式 jdk 0 , json 1
        out.writeByte(0);
        // 4. 1 字节的 指令类型（消息类型）
        out.writeByte(msg.getMessageType());
        // 填充字节，对齐填充(使得数据头字节数为2的整数倍) 4 + 1 + 1 + 1 + 4 + 4 = 15 (再补充一个字节即可)
        out.writeByte(0xff);
        // 5. 4 个字节 序列号
        out.writeInt(msg.getSequenceId());
        // 6. 获取msg内容的字节数组(msg对象转换为字节数组)
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(msg);
        byte[] bytes = bos.toByteArray();
        // 7. 长度 4 个字节
        out.writeInt(bytes.length);


        // 8. 写入内容
        out.writeBytes(bytes);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 魔数
        int magicNum = in.readInt();
        // 版本号
        byte version = in.readByte();
        // 序列化方式
        byte serializerType = in.readByte();
        // 消息类型
        byte messageType = in.readByte();
        // 填充字节
        in.readByte();
        // 序列号
        int sequenceId = in.readInt();
        // 内容长度
        int length = in.readInt();

        // 读取 主体内容 字节数组
        byte[] bytes = new byte[length];
        in.readBytes(bytes, 0, length);

        // 将 主体内容字节数组 反序列化为 Message对象
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
        Message message = (Message) ois.readObject();

        // 日志
        log.debug("magicNum:{}, version:{}, serializerType:{}, messageType:{}, sequenceId:{}, length:{}"
                , magicNum, version, serializerType, messageType, sequenceId, length);
        log.debug("message:{}", message);

        // 将 主体内容 放入输出列表中（解码只保留主体内容的Message对象）
        out.add(message);
    }
}